package com.smartdo.crawler.utils;

import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONNull;
import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.DeleteResult;
import org.bson.Document;
import org.bson.conversions.Bson;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static com.mongodb.client.model.Projections.fields;
import static com.mongodb.client.model.Projections.include;

/**
 * mongodb工具类
 */
public class MongodbUtils {

    public MongoClient mongoClient = null;
    MongoDatabase db = null;

    private MongodbUtils() {
        if (mongoClient == null) {
            try {
                //数据库连接实例
//                MongoCredential credential = MongoCredential.createCredential("admin", "admin", "admin!@#".toCharArray());
//                mongoClient = new MongoClient(new ServerAddress(
//                        PropertiesUtil.getPropertie("mongodb_hosts"),
//                        Convert.toInt(PropertiesUtil.getPropertie("mongodb_port"), 27017)),
//                        Arrays.asList(credential));
                mongoClient = new MongoClient(PropertiesUtil.getPropertie("mongodb_hosts"),
                        Convert.toInt(PropertiesUtil.getPropertie("mongodb_port"), 27017));
            } catch (MongoException e) {
                e.printStackTrace();
            }
        }
    }

    public void insertOne(String dbName, String collectionName, Map<String, Object> data) {
        MongoCollection<Document> dbCollection = null;
        db = mongoClient.getDatabase(dbName);
        if (data != null) {
            dbCollection = db.getCollection(collectionName);
            Document insertObj = new Document();
            for (String key : data.keySet()) {
                if (data.get(key) instanceof JSONNull) {
                    insertObj.append(key, null);
                } else {
                    insertObj.append(key, data.get(key));
                }
            }
            try {
                dbCollection.insertOne(insertObj);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //类初始化时，自行实例化，饿汉式单例模式
    private static final MongodbUtils mongoDBDaoImpl = new MongodbUtils();

    /**
     * 描述：单例的静态工厂方法
     *
     * @return
     */
    public static MongodbUtils getMongoDBInstance() {
        return mongoDBDaoImpl;
    }

    public void insertBatch(String dbName, String collectionName, List<Map<String, Object>> dataList) {
        MongoCollection<Document> dbCollection = null;
        db = mongoClient.getDatabase(dbName);
        if (dataList != null) {
            if (dataList.size() == 0) {
                return;
            }
            List<Document> insertList = new ArrayList<Document>();
            dbCollection = db.getCollection(collectionName);    //获取数据库中指定的collection集合
            for (Map<String, Object> data : dataList) {
                Document insertObj = new Document();
                for (String key : data.keySet()) {
                    if (data.get(key) instanceof JSONNull) {
                        insertObj.append(key, "");
                    } else {
                        insertObj.append(key, data.get(key));
                    }
                }
                insertList.add(insertObj);
            }
            try {
                dbCollection.insertMany(insertList);
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
    }
    public void insertMany(String dbName, String collectionName, List<Document> dataList) {
        MongoCollection<Document> dbCollection = null;
        db = mongoClient.getDatabase(dbName);
        if (dataList != null) {
            if (dataList.size() == 0) {
                return;
            }
            List<Document> insertList = new ArrayList<Document>();
            dbCollection = db.getCollection(collectionName);    //获取数据库中指定的collection集合
            for (Map<String, Object> data : dataList) {
                Document insertObj = new Document();
                for (String key : data.keySet()) {
                    if (data.get(key) instanceof JSONNull) {
                        insertObj.append(key, "");
                    } else {
                        insertObj.append(key, data.get(key));
                    }
                }
                insertList.add(insertObj);
            }
            try {
                dbCollection.insertMany(insertList);
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
    }

    /**
     * 批量修改文档记数，每个文档记数
     *
     * @param collectionName
     * @param field
     * @param ids
     * @param dt_code
     * @param counts
     */
    public void updateBatchById(String dbName, String collectionName, String field, List<String> ids, String dt_code, List<Integer> counts) {
        MongoCollection<Document> dbCollection = null;
        db = mongoClient.getDatabase(dbName);
        if (ids != null) {
            if (ids.size() == 0) {
                return;
            }
            dbCollection = db.getCollection(collectionName);    //获取数据库中指定的collection集合
            try {
                for (int i = 0; i < ids.size(); i++) {
                    Document update1 = new Document().append(dt_code, counts.get(i));
                    Document update = new Document("$inc", update1);
                    dbCollection.updateOne(Filters.eq(field, ids.get(i)), update);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 修改数据
     *
     * @param dbName
     * @param collectionName
     * @param condition      条件
     * @param data           数据
     */
    public void updateOne(String dbName, String collectionName, Bson condition, Document data) {
        MongoCollection<Document> dbCollection = null;
        db = mongoClient.getDatabase(dbName);
        dbCollection = db.getCollection(collectionName);    //获取数据库中指定的collection集合
        dbCollection.replaceOne(condition, data);
    }


    /**
     * 修改数据
     *
     * @param dbName
     * @param collectionName
     * @param condition      条件
     * @param data           数据
     */
    public void updateOrInster(String dbName, String collectionName, Bson condition, Document data) {
        MongoCollection<Document> dbCollection = null;
        db = mongoClient.getDatabase(dbName);
        dbCollection = db.getCollection(collectionName);    //获取数据库中指定的collection集合
        dbCollection.deleteOne(condition);
        dbCollection.insertOne(data);
    }


    /**
     * 单条修改计数器
     *
     * @param collectionName
     * @param fliter
     * @param key
     * @param inc
     */
    public void updateOneInc(String dbName, String collectionName, Bson fliter, String key, int inc) {
        db = mongoClient.getDatabase(dbName);
        MongoCollection<Document> dbCollection = db.getCollection(collectionName);
        Document update1 = new Document().append(key, inc);
        Document update = new Document("$inc", update1);
        dbCollection.updateOne(fliter, update);
    }

    /**
     * 查询单条记录
     *
     * @param collectionName：集合名
     * @param bson：查询条件->        Filters.eq("index_key", "张琴")
     * @return
     */
    public Document findOne(String dbName, String collectionName, Bson bson) {
        List<Document> list = find(dbName, collectionName, bson, 0, 1);
        Document document = null;
        if (list.size() == 1) {
            document = list.get(0);
        }
        return document;
    }


    /**
     * 数据查询
     *
     * @param collectionName：集合名
     * @param bson：查询条件->        Filters.eq("index_key", "张琴")
     * @param skip:查询开始
     * @param limit：限制条数
     * @return
     */
    public List<Document> find(String dbName, String collectionName, Bson bson, int skip, int limit) {
        List<Document> list = new ArrayList<Document>();
        db = mongoClient.getDatabase(dbName);
        try {
            MongoCollection<Document> dbCollection = db.getCollection(collectionName);
            MongoCursor<Document> cursor = dbCollection.find(bson).skip(skip).limit(limit).iterator();
            while (cursor.hasNext()) {
                Document document = cursor.next();
                list.add(document);
            }
        } catch (Exception e) {

        }
        return list;
    }

    public LinkedList<Document> findByLinked(String dbName, String collectionName, Bson bson, int skip, int limit) {
        LinkedList<Document> list = new LinkedList<>();
        db = mongoClient.getDatabase(dbName);
        try {
            System.out.println("");
            MongoCollection<Document> dbCollection = db.getCollection(collectionName);
            MongoCursor<Document> cursor = dbCollection.find(bson).skip(skip).limit(limit).iterator();
            while (cursor.hasNext()) {
                Document document = cursor.next();
                list.add(document);
            }
        } catch (Exception e) {
        }
        return list;
    }

    public LinkedList<Document> findByLinked(String dbName, String collectionName, Bson bson) {
        return findByLinked(dbName, collectionName, bson, 0, Integer.MAX_VALUE);
    }

    public List<Document> find(String dbName, String collectionName, Bson bson) {
        return find(dbName, collectionName, bson, 0, Integer.MAX_VALUE);
    }

    /**
     * 数据查询
     *
     * @param collectionName：集合名
     * @param bson：查询条件->        Filters.eq("index_key", "张琴")
     * @param projection         需要显示的字段
     * @return
     */
    public List<Document> find(String dbName, String collectionName, Bson bson, String... projection) {
        List<Document> list = new ArrayList<Document>();
        db = mongoClient.getDatabase(dbName);
        try {
            MongoCollection<Document> dbCollection = db.getCollection(collectionName);
            MongoCursor<Document> cursor = dbCollection.find(bson).projection(fields(include(projection))).iterator();
            while (cursor.hasNext()) {
                Document document = cursor.next();
                list.add(document);
            }
        } catch (Exception e) {

        }
        return list;
    }

    /**
     * 删除单条数据
     *
     * @param collectionName
     * @param bson：条件
     * @return
     */
    public long delData(String dbName, String collectionName, Bson bson) {
        db = mongoClient.getDatabase(dbName);
        MongoCollection<Document> dbCollection = db.getCollection(collectionName);
        DeleteResult deleteResult = dbCollection.deleteMany(bson);
        return deleteResult.getDeletedCount();
    }

    /**
     * 关闭连接
     */
    public void close() {
        //mongoClient.close();
    }
}